﻿// NumberKeyBoardDlg.cpp: 实现文件
//

#include "stdafx.h"
#include "DC-QC.h"
#include "NumberKeyBoardDlg.h"
#include "afxdialogex.h"

#define HIGHLIGHTTEXTCOLOR  RGB(255,200,0)
#define TOPEDITHEIGHT 50
// CNumberKeyBoardDlg 对话框

IMPLEMENT_DYNAMIC(CNumberKeyBoardDlg, CDialogEx)

CNumberKeyBoardDlg::CNumberKeyBoardDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_NUMKEYBOARDDLG, pParent)
{
	m_strInput = _T("");
	m_rtArea = CRect(0, 0, 0, 0);
	m_pFont.CreatePointFont(180, _T("微软雅黑"));
	m_nLeft = 0;;
	m_nTop = 0;
}

CNumberKeyBoardDlg::~CNumberKeyBoardDlg()
{
}

void CNumberKeyBoardDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CNumberKeyBoardDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_WM_CLOSE()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_MOUSEWHEEL()
	ON_WM_DESTROY()
	ON_WM_ACTIVATE()
	ON_WM_SETFOCUS()
	ON_WM_NCACTIVATE()
	ON_WM_MOUSEACTIVATE()
END_MESSAGE_MAP()


// CNumberKeyBoardDlg 消息处理程序
BOOL CNumberKeyBoardDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	if (m_nLeft != 0 || m_nTop != 0)
	{
		CRect rt;
		GetClientRect(rt);
		MoveWindow(m_nLeft, m_nTop + 20, rt.Width(), rt.Height());
	}
	else
		SetWindowPos(&wndTopMost, 0, 0, 0, 0,  //把窗口放到最顶端
			SWP_NOSIZE | SWP_NOMOVE);

	LOGFONT temp;
	memset(&temp, 0, sizeof(LOGFONT));       // zero out structure
	temp.lfHeight = 24;                      // request a 12-pixel-height font
	temp.lfWeight = 800;
	wcscpy_s(temp.lfFaceName, _T("Arial"));        // request a face name "Arial"
	VERIFY(m_TextFont.CreateFontIndirect(&temp));  // create the font

	FillBkBrushColor();

	gFocus = NULL;

	AddKey(0x00, 0x00, 0); //signal row change
	AddKey('1', '!', 10);
	AddKey('2', '@', 10);
	AddKey('3', '#', 10);
	AddKey('-', '_', 10);
	AddKey(0x00, 0x00, 1); //signal row change
	AddKey('4', '$', 10);
	AddKey('5', '%', 10);
	AddKey('6', '^', 10);
	AddKey('.', '>', 10);
	AddKey(0x00, 0x00, 2); //signal row change
	AddKey('7', '&', 10);
	AddKey('8', '*', 10);
	AddKey('9', '(', 10);
	AddKey('0', ')', 10);
	AddKey(0x00, 0x00, 3); //signal row change
	AddKey(0x00, BSPACE, 20); //backspace
	AddKey(0x00, CLOSE, 20);


	CalcWidthHeight();  //计算窗口中按键大小
	CalKeyRect();  //保存每一个按键的位置

	return TRUE;  // 除非设置了控件的焦点，否则返回 TRUE
}

void CNumberKeyBoardDlg::DrawInBorder(CDC* pDC, CRect rt, COLORREF tc, COLORREF bc)
{
	CPen pent, penb;
	pent.CreatePen(PS_SOLID, 1, tc);
	penb.CreatePen(PS_SOLID, 1, bc);
	CPen* oldPen = pDC->SelectObject(&pent);
	pDC->MoveTo(rt.right - 1, rt.top);
	pDC->LineTo(rt.left, rt.top);
	pDC->LineTo(rt.left, rt.bottom);

	pDC->MoveTo(rt.right - 2, rt.top + 1);
	pDC->LineTo(rt.left + 1, rt.top + 1);
	pDC->LineTo(rt.left + 1, rt.bottom - 1);

	pDC->SelectObject(&penb);
	pDC->MoveTo(rt.right, rt.top + 1);
	pDC->LineTo(rt.right, rt.bottom);
	pDC->LineTo(rt.left, rt.bottom);

	pDC->MoveTo(rt.right - 1, rt.top + 2);
	pDC->LineTo(rt.right - 1, rt.bottom - 1);
	pDC->LineTo(rt.left + 1, rt.bottom - 1);
	rt.DeflateRect(2, 2);
	pDC->FillSolidRect(rt, RGB(188, 188, 252));

	CFont* pOldFont = pDC->SelectObject(&m_pFont);
	pDC->SetBkMode(TRANSPARENT);
	//井深
	pDC->SetTextColor(RGB(210, 0, 0));
	pDC->DrawText(m_strInput, rt, DT_RIGHT);

	pDC->SelectObject(pOldFont);
	pDC->SelectObject(oldPen);
}


void CNumberKeyBoardDlg::CalcWidthHeight()
{
	pKeyWidth = 0;
	pKeyHeight = 0;
	KEYDEF * key;
	POSITION pos = cKeys.GetHeadPosition();
	long totalWidth = 0;
	long longest = 0;
	long rows = 0;
	while (pos)
	{
		key = cKeys.GetNext(pos);
		if ((key->cNormal == 0x00) && (key->cShifted == 0x00))
		{
			rows++;
			if (totalWidth > longest)
			{
				longest = totalWidth;
			}
			totalWidth = 0;
		}
		else
		{
			totalWidth += abs(key->cWidth);
		}
	}
	CRect rect;
	GetClientRect(rect);
	pKeyHeight = (rect.Height() - TOPEDITHEIGHT) / rows;		//这里是为了留出最上面的一行
	pKeyWidth = (int)(((double)rect.Width()) / ((((double)(longest)) / 10)));

	m_rtArea = CRect(CPoint(12, 10), CSize(rect.Width() - 23, TOPEDITHEIGHT - 20));
}

void CNumberKeyBoardDlg::AddKey(char pNormal, char pShifted, int pWidth)
{
	KEYDEF * key = new KEYDEF;
	key->cNormal = pNormal;
	key->cShifted = pShifted;
	key->cWidth = pWidth;
	key->bHighlight = false;
	key->rect.SetRect(0, 0, 0, 0);
	cKeys.AddTail(key);
}

void CNumberKeyBoardDlg::DrawKey(CDC * dc, KEYDEF * key)
{
	CString label = _T(" ");
	BOOL special = FALSE;
	CRect rc = key->rect;

	if (key->cNormal == 0x00 && key->cShifted == 0x00)
		return;

	COLORREF OldColor = dc->GetTextColor();
	CPen Pen, TextPen;
	CPen *pOldPen = NULL;
	if (!key->bHighlight)  //没有高亮显示
	{
		rc.DeflateRect(1, 1);
		DoGradientFill(dc, &rc);
		dc->Draw3dRect(rc, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DDKSHADOW));
		rc.DeflateRect(1, 1);
		dc->Draw3dRect(rc, GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_3DSHADOW));
	}
	else
	{
		rc.DeflateRect(1, 1);
		dc->FillSolidRect(rc, RGB(0x20, 0xff, 0x99));  //鼠标在上面的时候填充颜色
		dc->Draw3dRect(rc, GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_3DSHADOW));
		rc.DeflateRect(1, 1);
		dc->Draw3dRect(rc, GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DDKSHADOW));
		dc->SetTextColor(HIGHLIGHTTEXTCOLOR);
		Pen.CreatePen(PS_SOLID, 1, HIGHLIGHTTEXTCOLOR);
		pOldPen = dc->SelectObject(&Pen);
	}

	rc.DeflateRect(3, 1);

	CFont *pOldFont = dc->SelectObject(&m_TextFont);		//按键的字体颜色和大小
	dc->SetTextColor(RGB(0x88, 0x22, 0x11));
	TextPen.CreatePen(PS_SOLID, 2, RGB(0x88, 0x22, 0x11)); //绘制方向键的颜色和大小
	pOldPen = dc->SelectObject(&TextPen);

	if (key->cNormal == 0x00)
	{

		if (key->cShifted > 0x6F) //is a function
		{
			int fkeynum = key->cShifted - 0x6F;
			label.Format(_T("F%d"), fkeynum);
		}
		else
		{
			switch (key->cShifted)
			{
			case BSPACE:    // 0x06
				label = _T("删除");
				break;
			case ENTER:    // 0x07
				label = _T("确认");
				break;
			case CLOSE: //0x15
				label = _T("确认");
				break;
			case EMPTY:
				label = _T(" ");
				break;
			}
		}
		if (!special)
		{
			CSize tsize;
			tsize = dc->GetTextExtent(label);
			dc->TextOut(
				((rc.left + rc.right) / 2) - (tsize.cx / 2),
				((rc.top + rc.bottom) / 2) - (tsize.cy / 2),
				label);
		}
	}
	else
	{
		if ((key->cShifted >= 'A') && (key->cShifted <= 'Z'))
		{
			CSize tsize;
			label.Format(_T("%c"), key->cShifted);
			tsize = dc->GetTextExtent(label);
			dc->TextOut(
				((rc.left + rc.right) / 2) - (tsize.cx / 2),
				((rc.top + rc.bottom) / 2) - (tsize.cy / 2),
				label);
		}
		else
		{
			CSize tsize;
			label.Format(_T("%c"), key->cNormal);
			tsize = dc->GetTextExtent(label);
			dc->TextOut(
				((rc.left + rc.right) / 2) - (tsize.cx / 2),
				((rc.top + rc.bottom) / 2) - (tsize.cy / 2),
				label);
		}
	}
	dc->SetTextColor(OldColor);
	dc->SelectObject(pOldFont);
	if (pOldPen)
		dc->SelectObject(pOldPen);
}


// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CNumberKeyBoardDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
		DrawKeyboard();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标显示。
HCURSOR CNumberKeyBoardDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



//********************************************************
// 函数功能 ：当窗口切换的时候，保存当前键盘输入焦点窗口句柄
// 入口参数 ：
//
// 返回参数 ：
//
// 创建日期 ： 2005-1-26 16:54:20
// 作者     ： 杨奎     Mail: yangkui@seu.edu.cn
//********************************************************
BOOL CNumberKeyBoardDlg::PreTranslateMessage(MSG* pMsg)
{
	HWND wnd = ::GetForegroundWindow();
	if (IsWindow(wnd))
	{
		if (wnd != this->m_hWnd)
		{
			if (gFocus != wnd)
			{
				if (IsWindow(gFocus))
				{
					AttachThreadInput(
						GetCurrentThreadId(),
						GetWindowThreadProcessId(gFocus, NULL),
						FALSE);
				}

				gFocus = wnd;
				AttachThreadInput(
					GetCurrentThreadId(),
					GetWindowThreadProcessId(gFocus, NULL),
					TRUE);
			}
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}

void CNumberKeyBoardDlg::ReleaseFocus()
{
	if (IsWindow(gFocus))
	{
		HWND wnd = ::GetForegroundWindow();
		if (IsWindow(wnd))
		{
			if (wnd == gFocus)
			{
				return;
			}
		}
		::SetForegroundWindow(gFocus);
	}
}

void CNumberKeyBoardDlg::PostNcDestroy()
{
	CDialog::PostNcDestroy();
}

BOOL CNumberKeyBoardDlg::PreCreateWindow(CREATESTRUCT& cs)
{
	return CDialog::PreCreateWindow(cs);
}

//********************************************************
// 函数功能 ：把按键发内容送到指定窗口中去
// 入口参数 ：
//
// 返回参数 ：
//
// 创建日期 ： 2005-1-26 20:18:23
// 作者     ： 杨奎     Mail: yangkui@seu.edu.cn
//********************************************************
void CNumberKeyBoardDlg::SendKey(KEYDEF * keydef)
{
	if (keydef->cNormal == 0x00)
	{
		int vk;
		BOOL uptoo = TRUE;
		if (keydef->cShifted > 0x6F) //is a function key
		{
			vk = keydef->cShifted;
		}
		else
		{
			switch (keydef->cShifted)  //判断功能键的类型
			{
			case BSPACE:    // 0x06
				vk = VK_BACK;
				m_strInput = m_strInput.Left(m_strInput.GetLength() - 1);
				break;
			case CLOSE: //0x15
				CDialog::OnOK();
				break;
			}
		}
	}
	else
	{
		char pChar = keydef->cNormal;
		m_strInput = m_strInput + (CString)pChar;
	}
	InvalidateRect(m_rtArea);
}

//********************************************************
// 函数功能 ：获取当前shift，ctrl和caps的状态
// 入口参数 ：无
//
// 返回参数 ：如果第一位为1表示capital按下，如果第二位为1表示shift按下
//				如果第三位按下的话，表示control按下
// 创建日期 ： 2005-1-26 20:18:55
// 作者     ： 杨奎     Mail: yangkui@seu.edu.cn
//********************************************************
int CNumberKeyBoardDlg::DescribeKeyState()
{
	int state = 0;
	short ks;
	ks = GetKeyState(VK_CAPITAL);
	if (ks & 0x000F) state += 0x01;
	ks = GetKeyState(VK_SHIFT);
	if (ks & 0xF000) state += 0x02;
	ks = GetKeyState(VK_CONTROL);
	if (ks & 0xF000) state += 0x04;
	return state;
}
//********************************************************
// 函数功能 ：绘制所有的按键
// 入口参数 ：
//
// 返回参数 ：
//
// 创建日期 ： 2005-1-26 20:20:56
// 作者     ： 杨奎     Mail: yangkui@seu.edu.cn
//********************************************************
void CNumberKeyBoardDlg::DrawKeyboard()
{
	CClientDC dc(this);
	CRect client;
	GetClientRect(client);
	CRgn clipRgn;
	clipRgn.CreateRectRgnIndirect(&client);
	dc.SelectClipRgn(&clipRgn);
	dc.SelectObject(GetStockObject(DEFAULT_GUI_FONT));
	dc.SetBkMode(TRANSPARENT);
	KEYDEF * key;
	POSITION pos = cKeys.GetHeadPosition();
	cCurrentKeyState = DescribeKeyState();
	int state = cCurrentKeyState;
	while (pos)
	{
		key = cKeys.GetNext(pos);
		if (key->cNormal == 0x00)
		{
			switch (key->cShifted)
			{
			case CAPSLOCK:
				key->bHighlight = false;
				if (state & 0x01)
				{
					key->bHighlight = true;
				}
				break;
			case SHIFT:
				key->bHighlight = false;
				if (state & 0x02)
				{
					key->bHighlight = true;
				}
				break;
			case CTRL:
				key->bHighlight = false;
				if (state & 0x04)
				{
					key->bHighlight = true;
				}
				break;
			default:
				break;
			}
		}
		DrawKey(&dc, key);
	}
	DrawInBorder(&dc, m_rtArea);
}

// 计算按键的矩形区域
void CNumberKeyBoardDlg::CalKeyRect(void)
{
	CRect client;
	GetClientRect(client);
	int x = 0;
	int y = -pKeyHeight + TOPEDITHEIGHT;
	KEYDEF * key;
	POSITION pos = cKeys.GetHeadPosition();
	while (pos)
	{
		key = cKeys.GetNext(pos);
		if ((key->cNormal == 0x00) && (key->cShifted == 0x00))
		{
			x = 0;
			y += pKeyHeight;
		}
		else
		{
			int width = ((abs(key->cWidth) * pKeyWidth) / 10);
			CRect rc(x, y, x + width, y + pKeyHeight);
			if (key->cWidth < 0)
			{
				rc.right = client.right;
			}
			x += width;
			key->rect = rc;
		}
	}
}

void CNumberKeyBoardDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	ReleaseFocus();
	CClientDC dc(this);
	dc.SelectObject(GetStockObject(DEFAULT_GUI_FONT));
	dc.SetBkMode(TRANSPARENT);
	KEYDEF * key;
	POSITION pos = cKeys.GetHeadPosition();
	cCurrentKeyState = DescribeKeyState();
	int state = cCurrentKeyState;
	while (pos)
	{
		key = cKeys.GetNext(pos);
		if (key->rect.PtInRect(point))  //鼠标在按键上
		{
			if (key->bHighlight != true)
			{
				key->bHighlight = true;
				DrawKey(&dc, key);
			}
		}
		else if (key->bHighlight == true)  //不在你上面你也亮的话
		{
			if (key->cNormal == 0x00) //判断是不是shift,ctrl,caps
			{
				switch (key->cShifted)
				{
				case CAPSLOCK:
					if (!(state & 0x01))  //根据当前状态不应该亮的
					{
						key->bHighlight = false;  //关掉
						DrawKey(&dc, key);
					}
					break;
				case SHIFT:
					if (!(state & 0x02))  //不应该亮的
					{
						key->bHighlight = false;  //关掉
						DrawKey(&dc, key);
					}
					break;
				case CTRL:
					if (!(state & 0x04))  //不应该亮的
					{
						key->bHighlight = false;  //关掉
						DrawKey(&dc, key);
					}
					break;
				default:
					key->bHighlight = false;  //其它功能键关掉
					DrawKey(&dc, key);
					break;
				}
			}
			else
			{
				key->bHighlight = false;  //不是功能键关掉
				DrawKey(&dc, key);
			}
		}
	}
}

void CNumberKeyBoardDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	if (IsWindow(gFocus))
	{
		::SetActiveWindow(gFocus);
	}
	return;
}

void CNumberKeyBoardDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	ReleaseFocus();

	CClientDC dc(this);
	dc.SelectObject(GetStockObject(DEFAULT_GUI_FONT));
	dc.SetBkMode(TRANSPARENT);
	KEYDEF * key;
	POSITION pos = cKeys.GetHeadPosition();
	while (pos)
	{
		key = cKeys.GetNext(pos);
		if (key->rect.PtInRect(point))
		{
			SendKey(key);
			DrawKey(&dc, key);
			return;
		}
	}
}

void CNumberKeyBoardDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	OnLButtonDown(nFlags, point);
}

void CNumberKeyBoardDlg::OnRButtonDown(UINT nFlags, CPoint point)
{
	OnLButtonDown(nFlags, point);
}

void CNumberKeyBoardDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
	OnLButtonUp(nFlags, point);
}

void CNumberKeyBoardDlg::OnRButtonDblClk(UINT nFlags, CPoint point)
{
	OnLButtonDown(nFlags, point);
}

BOOL CNumberKeyBoardDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	//	ReleaseFocus();
	return TRUE;
}

void CNumberKeyBoardDlg::OnClose()
{
	CDialog::OnClose();
}


void CNumberKeyBoardDlg::OnDestroy()
{
	CDialog::OnDestroy();

	FreeBkBrushColor();

	POSITION pos = cKeys.GetHeadPosition();
	while (pos)
	{
		delete cKeys.GetNext(pos);
	}
	int state = DescribeKeyState();
	if (state & 0x01) keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
	if (state & 0x02) keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
	if (state & 0x04) keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
}

/*
这几个函数的作用是屏蔽键盘对话框被激活
可以去除原来接受消息窗口闪烁的现象
*/
void CNumberKeyBoardDlg::OnSetFocus(CWnd* pOldWnd)
{
	CDialog::OnSetFocus(pOldWnd);
}

void CNumberKeyBoardDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
	if (nState == WA_CLICKACTIVE && pWndOther != NULL)
	{
		::SetActiveWindow(pWndOther->GetSafeHwnd());
		return;
	}

	CDialog::OnActivate(nState, pWndOther, bMinimized);
}

BOOL CNumberKeyBoardDlg::OnNcActivate(BOOL bActive)
{
	return CDialog::OnNcActivate(bActive);
}

//重点是这个函数，返回-1的时候，窗口不会闪烁
int CNumberKeyBoardDlg::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
	return MA_NOACTIVATE;
	//	return CDialog::OnMouseActivate(pDesktopWnd, nHitTest, message);
}



//初始化按钮背景颜色数据
void CNumberKeyBoardDlg::FillBkBrushColor()
{
	for (int i = 0; i < 64; i++)
	{
		m_BTBkColor[i].CreateSolidBrush(RGB(155 - i / 2, 155 - i / 2, 155 - i / 2));
	}
}

//释放背景颜色数据
void CNumberKeyBoardDlg::FreeBkBrushColor()
{
	for (int i = 0; i < 64; i++)
		m_BTBkColor[i].DeleteObject();
}

//绘制渐变的按钮形状
void CNumberKeyBoardDlg::DoGradientFill(CDC *pDC, CRect* rect)
{
	CRect rct;

	int nWidth = rect->Width();
	int nHeight = rect->Height();

	for (int i = rect->top; i <= rect->bottom; i++)
	{
		rct.SetRect(rect->left, i, rect->right, i + 1);
		pDC->FillRect(&rct, &m_BTBkColor[((i - rect->top) * 63) / nHeight]);
	}
}
